StalactiteRepositoryFactory.java
package org.codefilarete.stalactite.spring.repository;
import javax.annotation.Nullable;
import java.lang.reflect.Method;
import java.util.Optional;
import org.codefilarete.stalactite.engine.runtime.AdvancedEntityPersister;
import org.codefilarete.stalactite.spring.repository.query.CreateQueryLookupStrategy;
import org.codefilarete.stalactite.spring.repository.query.bean.BeanQueryLookupStrategy;
import org.codefilarete.stalactite.spring.repository.query.nativ.NativeQueryLookupStrategy;
import org.codefilarete.stalactite.sql.ConnectionProvider;
import org.codefilarete.stalactite.sql.Dialect;
import org.codefilarete.tool.bean.Objects;
import org.codefilarete.tool.collection.Arrays;
import org.codefilarete.tool.collection.Iterables;
import org.codefilarete.tool.exception.NotImplementedException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.data.projection.ProjectionFactory;
import org.springframework.data.repository.core.EntityInformation;
import org.springframework.data.repository.core.NamedQueries;
import org.springframework.data.repository.core.RepositoryInformation;
import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
import org.springframework.data.repository.query.QueryLookupStrategy;
import org.springframework.data.repository.query.QueryLookupStrategy.Key;
import org.springframework.data.repository.query.QueryMethodEvaluationContextProvider;
import org.springframework.data.repository.query.RepositoryQuery;
/**
* Mimics JpaRepositoryFactory for Stalactite
*
* @author Guillaume Mary
*/
public class StalactiteRepositoryFactory extends RepositoryFactorySupport {
private final AdvancedEntityPersister<?, ?> entityPersister;
private final Dialect dialect;
private final ConnectionProvider connectionProvider;
private ListableBeanFactory beanFactory;
public StalactiteRepositoryFactory(AdvancedEntityPersister<?, ?> entityPersister,
Dialect dialect,
ConnectionProvider connectionProvider) {
this.entityPersister = entityPersister;
this.dialect = dialect;
this.connectionProvider = connectionProvider;
}
@Override
public <T, ID> EntityInformation<T, ID> getEntityInformation(Class<T> domainClass) {
// because I don't know in which case this method is invoked I throw an exception
throw new NotImplementedException("waiting for use case");
}
@Override
protected Object getTargetRepository(RepositoryInformation metadata) {
return new SimpleStalactiteRepository<>(entityPersister);
}
@Override
protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {
return SimpleStalactiteRepository.class;
}
/**
* Overridden to be capable of accessing the instance, because parent field is private :'(
* @param beanFactory owning BeanFactory (never {@code null}).
*/
@Override
public void setBeanFactory(BeanFactory beanFactory) {
this.beanFactory = (ListableBeanFactory) beanFactory;
}
@Override
protected Optional<QueryLookupStrategy> getQueryLookupStrategy(@Nullable QueryLookupStrategy.Key key,
QueryMethodEvaluationContextProvider evaluationContextProvider) {
switch (Objects.preventNull(key, Key.CREATE_IF_NOT_FOUND)) {
case CREATE:
return Optional.of(new CreateQueryLookupStrategy<>(entityPersister, dialect));
case USE_DECLARED_QUERY:
return Optional.of(new FirstMatchingQueryLookupStrategy(
new BeanQueryLookupStrategy<>(beanFactory, dialect),
new NativeQueryLookupStrategy<>(entityPersister, dialect, connectionProvider)));
case CREATE_IF_NOT_FOUND:
return Optional.of(new FirstMatchingQueryLookupStrategy(
new BeanQueryLookupStrategy<>(beanFactory, dialect),
new NativeQueryLookupStrategy<>(entityPersister, dialect, connectionProvider),
new CreateQueryLookupStrategy<>(entityPersister, dialect)));
default:
throw new IllegalArgumentException(String.format("Unsupported query lookup strategy %s!", key));
}
}
/**
* {@link QueryLookupStrategy} to try to detect a declared query first (
* {@link org.springframework.data.jpa.repository.Query}, JPA named query). In case none is found we fall back on
* query creation.
*
* @author Oliver Gierke
* @author Thomas Darimont
*/
private static class FirstMatchingQueryLookupStrategy implements QueryLookupStrategy {
private final Iterable<QueryLookupStrategy> lookupStrategies;
/**
* Creates a new {@link FirstMatchingQueryLookupStrategy}.
*
* @param lookupStrategies must not be {@literal null}.
*/
public FirstMatchingQueryLookupStrategy(QueryLookupStrategy... lookupStrategies) {
this.lookupStrategies = Arrays.asSet(lookupStrategies);
}
@Override
public RepositoryQuery resolveQuery(Method method, RepositoryMetadata metadata, ProjectionFactory factory, NamedQueries namedQueries) {
return Iterables.find(lookupStrategies, lookupStrategy -> lookupStrategy.resolveQuery(method, metadata, factory, namedQueries), java.util.Objects::nonNull).getRight();
}
}
}